package com.workflow.workflowproject.serviceImpl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSONObject;
import com.anwen.mongo.mapper.BaseMapper;
import com.anwen.mongo.service.impl.ServiceImpl;
import com.mybatisflex.core.query.QueryWrapper;
import com.workflow.workflowproject.entity.FlowField;
import com.workflow.workflowproject.entity.FlowForm;
import com.workflow.workflowproject.entity.FlowInfo;
import com.workflow.workflowproject.entity.FlowLogs;
import com.workflow.workflowproject.entity.dto.TaskDataDto;
import com.workflow.workflowproject.entity.dto.TaskInfoDto;
import com.workflow.workflowproject.entity.dto.UserInfoDto;
import com.workflow.workflowproject.entity.mongoEntity.FlowValue;
import com.workflow.workflowproject.entity.table.FlowFieldTableDef;
import com.workflow.workflowproject.entity.table.FlowFormTableDef;
import com.workflow.workflowproject.mapper.*;
import com.workflow.workflowproject.pojo.lowflow.FlowNodeField;
import com.workflow.workflowproject.pojo.lowflow.FlowNodeOption;
import com.workflow.workflowproject.pojo.lowflow.table.FlowNodeFieldTableDef;
import com.workflow.workflowproject.pojo.lowflow.table.FlowNodeOptionTableDef;
import com.workflow.workflowproject.service.TaskService;
import com.workflow.workflowproject.tools.Result.Result;
import com.workflow.workflowproject.until.LoginUserUtil;
import com.workflow.workflowproject.until.ShowInformation;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

@Service
public class TaskServiceImpl extends ServiceImpl<FlowValue> implements TaskService {
    @Autowired
    private ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    /**
     * 流程定义信息
     */
    @Autowired
    private FlowInfoMapper flowInfoMapper;
    /**
     * 流程文件信息
     */
    @Autowired
    private FlowFormMapper flowFormMapper;
    /**
     * 流程字段
     */
    @Autowired
    private FlowNodeFieldMapper flowNodeFieldMapper;
    /**
     * 流程节点操作
     */
    @Autowired
    private FlowNodeOptionMapper flowNodeOptionMapper;
    /**
     * 流程日志
     */
    @Autowired
    private FlowLogsMapper flowLogsMapper;
    /**
     * 获取节点操作
     *
     * @param
     * @return
     */
    @Override
    public Result getOption(TaskInfoDto taskInfo) throws Exception {
        org.flowable.engine.TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery().processInstanceId(taskInfo.getProcessInstanceId()).active().singleResult();
        if(ObjectUtil.isEmpty(task)){
            return Result.fail("该任务不存在，无法进行获取节点");
        }
        FlowNodeOption flowNodeOptionOne = flowNodeOptionMapper.selectOneById(task.getTaskDefinitionKey());
        return Result.ok(flowNodeOptionOne);
    }
    /**
     * 获取节点字段操作
     *
     * @param
     * @return
     */
    @Override
    public Result getFieldByNode(TaskInfoDto taskInfo) throws Exception {
        org.flowable.engine.TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery().processInstanceId(taskInfo.getProcessInstanceId()).active().singleResult();
        HashMap<String,FlowNodeField> flowNodeFieldHashMap = new HashMap<>();
        if(ObjectUtil.isNotEmpty(task)){
            QueryWrapper flowNodeFieldQueryWrapper = new QueryWrapper();
            flowNodeFieldQueryWrapper.where(FlowNodeFieldTableDef.FLOW_NODE_FIELD.TASK_NODE_ID.eq(task.getTaskDefinitionKey()));
            List<FlowNodeField> flowNodeFields = flowNodeFieldMapper.selectListByQuery(flowNodeFieldQueryWrapper);
            flowNodeFields.forEach(item->{
                flowNodeFieldHashMap.put(item.getFieldId(),item);
            });
        }
        //获取流程
        QueryWrapper flowFormQueryWrapper = new QueryWrapper();
        flowFormQueryWrapper.where(FlowFormTableDef.FLOW_FORM.FLOW_INFO_ID.eq(taskInfo.getFlowInfoId()));
        FlowForm flowForm = flowFormMapper.selectOneByQuery(flowFormQueryWrapper);
        //获取流程字段
        List<JSONObject> mvFormFields = flowForm.getMvFormJson();
        for(JSONObject field : mvFormFields){
            FlowNodeField flowNodeField = flowNodeFieldHashMap.get(field.getString("field"));
            if(ObjectUtil.isNotEmpty(flowNodeField)){
                if(flowNodeField.getHidden().compareTo(1) == 0){
                    //隐藏
                    field.put("type","hidden");
                }
                if(flowNodeField.getReadable().compareTo(1) != 0){
                    //只读
                    field.put("disabled",true);
                }
            }
        }
        List<JSONObject> pcFormFields = flowForm.getPcFormJson();
        for(JSONObject field : pcFormFields){
            FlowNodeField flowNodeField = flowNodeFieldHashMap.get(field.getString("field"));
            if(ObjectUtil.isNotEmpty(flowNodeField)){
                if(flowNodeField.getHidden().compareTo(1) == 0){
                    //隐藏
                    field.put("type","hidden");
                }
                if(flowNodeField.getReadable().compareTo(1) != 0){
                    //只读
                    field.put("disabled",true);
                }
            }
        }
        //数据返回
        HashMap<String,List<JSONObject>> fileJsonMap = new HashMap<>();
        fileJsonMap.put("pcRule",pcFormFields);
        fileJsonMap.put("mvRule",mvFormFields);
        return Result.ok(fileJsonMap);
    }

    /**
     * 发起申请
     *
     * @param
     * @return
     */
    @Override
    @Transactional
    public Result taskApply(TaskInfoDto taskInfo) throws Exception {
        UserInfoDto userInfoDto = LoginUserUtil.getUserInfo();
        FlowInfo flowInfo = flowInfoMapper.selectOneById(taskInfo.getFlowInfoId());
        if(ObjectUtil.isEmpty(flowInfo)){
            return Result.fail("流程定义不存在，无法进行申请");
        }
        FlowForm flowForm = flowFormMapper.selectOneById(flowInfo.getCurrentVersion());
        if(ObjectUtil.isEmpty(flowForm)){
            return Result.fail("流程文件不存在，无法进行申请");
        }
        String busKey = "";
        if(StringUtils.isNotBlank(taskInfo.getBusKey())){
            //-----如果提交申请时已经创建了业务ID，则说明该申请单是暂存或者再提交的订单，满足特殊业务-----//
            busKey = taskInfo.getBusKey();
        }else{
            //-----自定义业务ID-----//
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmSSS");
            busKey = simpleDateFormat.format(new Date());
        }
        //获取值
        JSONObject flowProcessValue = taskInfo.getValue();
        //设置一个空的流程审批人员
        flowProcessValue.put("Item","user");
        List<String> collections = new ArrayList<>();
        collections.add("user");
        flowProcessValue.put("Collection",collections);
        JSONObject value = taskInfo.getValue();
        // 启动流程实例通过 RuntimeService 对象
        RuntimeService runtimeService = processEngine.getRuntimeService();
        ProcessInstance processInstance = null;
        IdentityService identityService = processEngine.getIdentityService();
        //设置流程发起人
        try {
            identityService.setAuthenticatedUserId(userInfoDto.getUserId());
            processInstance = runtimeService.startProcessInstanceByKey(flowForm.getFlowId(),busKey,flowProcessValue);
        }finally {
            identityService.setAuthenticatedUserId(null);
        }
        //-----自定义流程翻译信息-----//
        SimpleDateFormat simpleDateFormatTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String message = ShowInformation.setShowInformation(flowInfo.getId(),busKey,"",flowInfo.getName(),simpleDateFormatTime.format(new Date()),value);
        //将busKey存入数据中
        FlowValue flowValue = new FlowValue();
        flowValue.setBusKey(busKey);
        flowValue.setValue(value);
        flowValue.setIsReadValue(message);
        flowValue.setProcessInstanceId(processInstance.getProcessInstanceId());
        flowValue.setFlowInfoId(taskInfo.getFlowInfoId());
        //保存输入，如果存在ID则更新，如果不存在则新增
        this.save(flowValue);
        return Result.ok();
    }
    /**
     * 数据暂存
     *
     * @param
     * @return
     */
    @Override
    @Transactional
    public Result saveData(TaskInfoDto taskInfo) throws Exception {
        FlowInfo flowInfo = flowInfoMapper.selectOneById(taskInfo.getFlowInfoId());
        if(ObjectUtil.isEmpty(flowInfo)){
            return Result.fail("流程定义不存在，无法进行申请");
        }
        //-----自定义业务ID-----//
        String busKey = null;
        if(StringUtils.isBlank(taskInfo.getBusKey())){
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
            busKey = flowInfo.getNo() + simpleDateFormat.format(new Date());
        }
        JSONObject value = taskInfo.getValue();
        //-----自定义流程翻译信息-----//
        SimpleDateFormat valueSimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String message = ShowInformation.setShowInformation(flowInfo.getId(),busKey,"",flowInfo.getName(),valueSimpleDateFormat.format(new Date()),value);
        //将busKey存入数据中

        //保存输入，如果存在ID则更新，如果不存在则新增
        if(StringUtils.isNotBlank(taskInfo.getBusKey())){
            FlowValue flowValue = this.getById(taskInfo.getBusKey());
            flowValue.setValue(value);
            flowValue.setIsReadValue(message);
            flowValue.setProcessInstanceId("");
            flowValue.setFlowInfoId(taskInfo.getFlowInfoId());
            this.updateById(flowValue);
        }else{
            FlowValue flowValue = new FlowValue();
            flowValue.setBusKey(busKey);
            flowValue.setValue(value);
            flowValue.setIsReadValue(message);
            flowValue.setProcessInstanceId("");
            flowValue.setFlowInfoId(taskInfo.getFlowInfoId());
            this.save(flowValue);
        }
        return Result.ok();
    }
    /**
     * 申请撤销
     *
     * @param
     * @return
     */
    @Override
    @Transactional
    public Result revokeTask(TaskInfoDto taskInfo) throws Exception {
        FlowInfo flowInfo = flowInfoMapper.selectOneById(taskInfo.getFlowInfoId());
        if(ObjectUtil.isEmpty(flowInfo)){
            return Result.fail("流程定义不存在，无法进行申请");
        }
        // 判断流程信息是否存在
        if(ObjectUtil.isEmpty(taskInfo.getProcessInstanceId())){
            return Result.fail("流程实例ID不存在，无法进行撤销");
        }
        // 判断流程信息是否存在
        if(ObjectUtil.isEmpty(taskInfo.getBusKey())){
            return Result.fail("流程业务ID不存在，无法进行撤销");
        }
        // 获取 RuntimeService 对象
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 删除该流程实例，流程信息不存在
        runtimeService.deleteProcessInstance(taskInfo.getProcessInstanceId(), "流程撤销");
        //流程数据不存在
        FlowValue flowValue = this.getById(taskInfo.getBusKey());
        //将流程ID置空，确保流程不存在
        flowValue.setProcessInstanceId("");
        //保存输入，如果存在ID则更新，如果不存在则新增
        this.updateById(flowValue);
        return Result.ok();
    }
    /**
     * 通过业务ID获取数据
     *
     * @param
     * @return
     */
    @Override
    public Result getTaskData(String busKey) throws Exception {
        //查询值
        FlowValue flowValue = this.getById(busKey);
        //构造设置值
        TaskInfoDto taskInfo = new TaskInfoDto();
        taskInfo.setBusKey(flowValue.getBusKey());
        taskInfo.setValue(flowValue.getValue());
        taskInfo.setProcessInstanceId(flowValue.getProcessInstanceId());
        taskInfo.setFlowInfoId(flowValue.getFlowInfoId());
        return Result.ok(taskInfo);
    }
    /**
     * 申请通过
     *
     * @param
     * @return
     */
    @Override
    @Transactional
    public Result passTask(TaskInfoDto taskInfo) throws Exception {
        org.flowable.engine.TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery().processInstanceId(taskInfo.getProcessInstanceId()).active().singleResult();
        if(ObjectUtil.isEmpty(task)){
            return Result.fail("该任务不存在，无法通过");
        }
        taskService.complete(task.getId(),taskInfo.getValue());
        return Result.ok();
    }
    /**
     * 申请驳回
     *
     * @param
     * @return
     */
    @Override
    @Transactional
    public Result rejectTask(TaskInfoDto taskInfo) throws Exception {
        org.flowable.engine.TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery().processInstanceId(taskInfo.getProcessInstanceId()).active().singleResult();
        if(ObjectUtil.isEmpty(task)){
            return Result.fail("该任务不存在，无法拒绝");
        }
        RuntimeService runtimeService = processEngine.getRuntimeService();
        runtimeService.deleteProcessInstance(taskInfo.getProcessInstanceId(), "该任务流程终止，流程已被拒绝");
        return Result.ok();
    }
    /**
     * 申请回退
     *
     * @param
     * @return
     */
    @Override
    @Transactional
    public Result returnTask(TaskInfoDto taskInfo) throws Exception {
        org.flowable.engine.TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery().processInstanceId(taskInfo.getProcessInstanceId()).active().singleResult();
        if(ObjectUtil.isEmpty(task)){
            return Result.fail("该任务不存在，无法回退");
        }
        if(StringUtils.isBlank(task.getTaskDefinitionKey())){
            return Result.fail("无回退节点，无法进行回退");
        }
        if(StringUtils.isBlank(taskInfo.getReturnTaskId())){
            return Result.fail("无回退节点，无法进行回退");
        }
        RuntimeService runtimeService = processEngine.getRuntimeService();
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(taskInfo.getProcessInstanceId()).singleResult();
        List<Execution> executions = runtimeService.createExecutionQuery()
                .processInstanceId(taskInfo.getProcessInstanceId())
                .activityId(task.getTaskDefinitionKey()) // 当前节点ID
                .list();
        for (Execution execution : executions) {
            runtimeService.createChangeActivityStateBuilder()
                    .processInstanceId(taskInfo.getProcessInstanceId())
                    .moveExecutionToActivityId(execution.getId(), taskInfo.getReturnTaskId())
                    .changeState();
        }
        FlowLogs flowLogs = new FlowLogs();
        flowLogs.setId(task.getId());
        flowLogs.setType("TASK_CREATED");
        flowLogs.setBusKey(processInstance.getBusinessKey());
        flowLogs.setProcessInstanceId(task.getProcessInstanceId());
        flowLogs.setNodeKey(task.getTaskDefinitionKey());
        flowLogs.setTaskName(task.getName());
        flowLogs.setResult("流程转发");
        flowLogs.setUserId("user");
        flowLogsMapper.insert(flowLogs);
        return Result.ok();
    }
    /**
     * 流程转交
     *
     * @param
     * @return
     */
    @Override
    @Transactional
    public Result passOnTask(TaskInfoDto taskInfo) throws Exception {
        org.flowable.engine.TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery().processInstanceId(taskInfo.getProcessInstanceId()).active().singleResult();
        if(ObjectUtil.isEmpty(task)){
            return Result.fail("该任务不存在，流程转交失败");
        }
        taskService.setAssignee(task.getId(), taskInfo.getPassOnUserId());
        return Result.ok();
    }
    /**
     * 流程委派
     *
     * @param
     * @return
     */
    @Override
    @Transactional
    public Result delegateTask(TaskInfoDto taskInfo) throws Exception {
        org.flowable.engine.TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery().processInstanceId(taskInfo.getProcessInstanceId()).active().singleResult();
        if(ObjectUtil.isEmpty(task)){
            return Result.fail("该任务不存在，流程委派失败");
        }
        taskService.delegateTask(task.getId(),taskInfo.getDelegateUserId());
        return Result.ok();
    }
    /**
     * 委派处理
     *
     * @param
     * @return
     */
    @Override
    @Transactional
    public Result delegatePassTask(TaskInfoDto taskInfo) throws Exception {
        org.flowable.engine.TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery().processInstanceId(taskInfo.getProcessInstanceId()).active().singleResult();
        if(ObjectUtil.isEmpty(task)){
            return Result.fail("该任务不存在，委派处理失败");
        }
        taskService.resolveTask(task.getId());
        return Result.ok();
    }
    /**
     * 获取创建任务
     *
     * @param
     * @return
     */
    @Override
    public Result getTaskByCreateUser(TaskDataDto taskDataDto) throws Exception {
        UserInfoDto user = LoginUserUtil.getUserInfo();
        HistoryService historyService = processEngine.getHistoryService();
        List<HistoricProcessInstance> historicProcessInstances =  historyService.createHistoricProcessInstanceQuery().startedBy(user.getUserId()).orderByProcessInstanceStartTime().desc()
                .listPage((taskDataDto.getPage() - 1) * taskDataDto.getLimit(), taskDataDto.getLimit());
        long total = historyService.createHistoricProcessInstanceQuery().startedBy(user.getUserId()).count();
        ArrayList<TaskDataDto> procIns = handleProcInsList(historicProcessInstances);
        return Result.ok(procIns,total);
    }
    /**
     * 获取待审批任务
     *
     * @param
     * @return
     */
    @Override
    public Result getTaskByAssigner(TaskDataDto taskDataDto) throws Exception {
        UserInfoDto user = LoginUserUtil.getUserInfo();
        org.flowable.engine.TaskService taskService = processEngine.getTaskService();
        List<Task> tasks = taskService.createTaskQuery().taskAssignee(user.getUserId())
                .orderByTaskCreateTime().desc()
                .listPage((taskDataDto.getPage() - 1) * taskDataDto.getLimit(), taskDataDto.getLimit());
        long total = taskService.createTaskQuery().taskAssignee(user.getUserId()).count();
        HistoryService historyService = processEngine.getHistoryService();
        List<HistoricProcessInstance> processInstances = new ArrayList<>();
        tasks.forEach(task -> {
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
            processInstances.add(historicProcessInstance);
        });
        ArrayList<TaskDataDto> procIns = handleProcInsList(processInstances);
        return Result.ok(procIns,total);
    }
    /**
     * 获取审批历史
     *
     * @param
     * @return
     */
    @Override
    public Result getHistoryTask(TaskDataDto taskDataDto) throws Exception {
        UserInfoDto user = LoginUserUtil.getUserInfo();
        HistoryService historyService = processEngine.getHistoryService();
        List<HistoricTaskInstance> hisTaskInsList = historyService.createHistoricTaskInstanceQuery()
                .finished()
                .taskAssignee(user.getUserId())
                .orderByTaskCreateTime().desc()
                .listPage((taskDataDto.getPage() - 1) * taskDataDto.getLimit(), taskDataDto.getLimit());
        long total = historyService.createHistoricTaskInstanceQuery()
                .finished()
                .taskAssignee(user.getUserId()).count();
        List<HistoricProcessInstance> processInstances = new ArrayList<>();
        hisTaskInsList.forEach(task -> {
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
            processInstances.add(historicProcessInstance);
        });
        ArrayList<TaskDataDto> procIns = handleProcInsList(processInstances);
        return Result.ok(procIns,total);
    }

    //遍历流程实例，获取任务信息
    public ArrayList<TaskDataDto> handleProcInsList(List<HistoricProcessInstance> list){
        HistoryService historyService = processEngine.getHistoryService();
        ArrayList<TaskDataDto> procList = new ArrayList<>();
        list.forEach(procIns -> {
            TaskDataDto proData = new TaskDataDto();
            proData.setStarter(procIns.getStartUserId());
            proData.setProInsId(procIns.getId());
            //查询申请原因 全局变量reason
            HistoricVariableInstance variableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(procIns.getId()).variableName("reason").singleResult();
            if (variableInstance != null) {
                proData.setReason(variableInstance.getValue().toString());
            }
            proData.setProcCreateTime(procIns.getEndTime());
            if (procIns.getEndTime() != null) {
                //整个流程已经结束
                proData.setProcEndTime(procIns.getEndTime());
                proData.setState("流程已结束");
            } else {
                //流程还没结束
                proData.setState("处理中...");
            }
        });
        return procList;
    }
}
